//
//  NativeBleChannel.m
//  kq_flutter_core_widget
//
//  Created by wtb on 2024/1/26.
//

#import "NativeBleChannel.h"

// 开始扫描蓝牙外设
static NSString *const startScanBle = @"startScanBle";
// 停止扫码蓝牙
static NSString *const stopScanBle = @"stopScanBle";
// 打开蓝牙
static NSString *const openBle = @"openBle";
// 关闭蓝牙
static NSString *const closeBle = @"closeBle";
// 蓝牙是否打开
static NSString *const isBleOpen = @"isBleOpen";
// 连接蓝牙设备
static NSString *const connectDevice = @"connectDevice";
// 断开蓝牙设备
static NSString *const disConnectDevice = @"disConnectDevice";
// 开始监听特征值
static NSString *const notify = @"notify";
// 取消监听特征值
static NSString *const unNotify = @"unNotify";
// 写入数据
static NSString *const writeCharacterData = @"writeCharacterData";


@implementation NativeBleChannel

+(void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar{
    FlutterMethodChannel *bleChannel = [FlutterMethodChannel methodChannelWithName:@"flutter.keqiang.com/ble" binaryMessenger:[registrar messenger]];
    NativeBleChannel *ble = [[NativeBleChannel alloc] init];
    [registrar addMethodCallDelegate:ble channel:bleChannel];
    
    ble.peripherals = [NSMutableDictionary dictionary];
    
    // 创建蓝牙开关监听对象
    ble.enableChannel = [NativeBleEnableChannel registerStateWithRegistrar:registrar];
    
    // 创建蓝牙连接监听对象
    ble.stateChannel = [NativeBleConnectStateChannel registerStateWithRegistrar:registrar];
    
    // 创建蓝牙扫描监听对象
    ble.scanChannel = [NativeBleScanChannel registerStateWithRegistrar:registrar];
    
    // 创建蓝牙数据交互监听对象
    ble.dataChannel = [NativeBleNotifyDataChannel registerStateWithRegistrar:registrar];
}

-(void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result{
    if ([startScanBle isEqualToString:call.method]) {
        // 开始扫描
        if (self.manager) {
            self.tag = call.arguments[@"tag"];
            int duration = 10;
            if (call.arguments[@"duration"]) {
                NSNumber *dur = call.arguments[@"duration"];
                duration = [dur intValue];
            }
            
            // 取消扫描超时定时器
            [self cancelScanTimer];
            
            // 开始扫描
            [self startScan];
            
            // 开始扫描倒计时
            [self performSelector:@selector(scanTimeout) withObject:nil afterDelay:duration];
            result(@1);
        }
    }else if([stopScanBle isEqualToString:call.method]){
        // 取消扫描超时定时器
        [self cancelScanTimer];
        
        // 停止扫码蓝牙
        [self stopScan];
        result(@1);
    }else if([openBle isEqualToString:call.method]){
        // 打开系统蓝牙（iOS无法通过代码打开系统蓝牙）
        result(@0);
    }else if([closeBle isEqualToString:call.method]){
        // 关闭系统蓝牙（iOS无法通过代码打开关闭蓝牙）
        [self stopScan];
        result(@0);
    }else if([isBleOpen isEqualToString:call.method]){
        // 蓝牙是否打开
        if (self.manager && self.isOpen) {
            result([NSNumber numberWithBool:self.isOpen]);
        }else{
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_global_queue(0, 0), ^{
                result([NSNumber numberWithBool:self.isOpen]);
            });
        }
    }else if([connectDevice isEqualToString:call.method]){
        self.flutterResult = result;
        // 连接蓝牙设备
        NSString *name = call.arguments[@"name"];
        self.name = name;
        NSString *macAddress = call.arguments[@"macAddress"];
        if (!name) {
            if (macAddress) {
                self.name = macAddress;
            }
        }
        // 连接超时时间
        NSInteger timeout = [call.arguments[@"timeoutMills"] integerValue]/1000;
        CBPeripheral *peripheral = nil;
        if (name) {
            // name有值，根据name查找
            peripheral = [self.peripherals objectForKey:name];
            if (peripheral) {
                // 有蓝牙设备
                self.peripheral = peripheral;
            }
        }else if(macAddress){
            // 如果有macAddress,则本地查找
            peripheral = [self.peripherals objectForKey:macAddress];
            if (peripheral) {
                // 有蓝牙设备
                self.peripheral = peripheral;
            }
        }
        if (peripheral) {
            if (peripheral.state == CBPeripheralStateConnected) {
                // 已经是在连接状态了
                self.isConnecting = NO;
                self.name = nil;
                result([self connectedGetDataWithPeripheral:peripheral]);
            }else{
                // 进行连接
                NSMutableDictionary *options = [NSMutableDictionary dictionary];
                [options setObject:[NSNumber numberWithBool:YES] forKey:CBConnectPeripheralOptionNotifyOnConnectionKey];
                [options setObject:[NSNumber numberWithBool:YES] forKey:CBConnectPeripheralOptionNotifyOnDisconnectionKey];
                [self.manager connectPeripheral:peripheral options:nil];
                [self performSelector:@selector(connectTimeout:) withObject:result afterDelay:timeout];
                self.isConnecting = YES;
            }
        }else{
            // 没有改设备去查找
            // 创建连接超时定时器
            self.isConnecting = YES;
            [self performSelector:@selector(connectTimeout:) withObject:result afterDelay:timeout];
        }
    }else if([disConnectDevice isEqualToString:call.method]){
        // 断开蓝牙设备
        NSString *macAddress = call.arguments[@"macAddress"];
        if (self.peripheral && [macAddress isEqualToString:self.peripheral.identifier.UUIDString]) {
            self.flutterResult = result;
            [self.manager cancelPeripheralConnection:self.peripheral];
        }
    }else if([notify isEqualToString:call.method]){
        // 开始监听特征值
        NSString *macAddress = call.arguments[@"macAddress"];
        self.service = call.arguments[@"service"];
        self.character = call.arguments[@"character"];
        self.flutterResult = result;
    }else if([unNotify isEqualToString:call.method]){
        // 取消监听特征值
        self.service = nil;
        self.character = nil;
        self.peripheral = nil;
        result(@1);
    }else if([writeCharacterData isEqualToString:call.method]){
        // 写入数据
        NSString *macAddress = call.arguments[@"macAddress"];
        self.service = call.arguments[@"service"];
        self.character = call.arguments[@"character"];
        
        CBService *service = nil;
        for (CBService *findService in [self.peripheral services]) {
            if ([findService.UUID.UUIDString isEqualToString:self.service]) {
                service = findService;
                break;
            }
        }
        NSArray *characteristics = [service characteristics];
        CBCharacteristic *characteristic = nil;
        for (CBCharacteristic *findCharacteristic in characteristics) {
            if ([findCharacteristic.UUID.UUIDString isEqualToString:self.character]) {
                characteristic = findCharacteristic;
                break;
            }
        }
        
        [self.peripheral writeValue:call.arguments[@"value"] forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];
    }
}


// 1.建立一个Central Manager实例进行蓝牙管理
-(CBCentralManager *)manager{
    if (!_manager) {
        _manager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
    }
    return _manager;
}

#pragma mark - 监听蓝牙是否开启
-(void)centralManagerDidUpdateState:(CBCentralManager *)central{
    switch (central.state) {
        case CBManagerStateUnknown:
        {
            // 初始化中
            self.isOpen = NO;
            [self sendBleState];
        }
            break;
        case CBManagerStateResetting:
        {
            // 设备不支持状态
            self.isOpen = NO;
            [self sendBleState];
        }
            break;
        case CBManagerStateUnsupported:
        {
            // 设备未授权状态
            self.isOpen = NO;
            [self sendBleState];
        }
            break;
        case CBManagerStateUnauthorized:
        {
            // 设备未授权状态
            self.isOpen = NO;
            [self sendBleState];
        }
            break;
        case CBManagerStatePoweredOn:
        {
            // 蓝牙已经打开
            self.isOpen = YES;
            [self sendBleState];
        }
            break;
        case CBManagerStatePoweredOff:
        {
            // 蓝牙未打开
            self.isOpen = NO;
            [self sendBleState];
        }
            break;
        default:
            break;
    }
}

#pragma mark - 蓝牙代理方法

// 2.搜索外围设备
// 扫描到的设备（RSSI是信号强度）
/**
 CBPeripheralStateDisconnected = 0,已断开/未连接
 CBPeripheralStateConnecting, 连接中
 CBPeripheralStateConnected, 已连接
 CBPeripheralStateDisconnecting 断开中
 */
-(void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI{
    
    if (self.scanChannel && self.scanChannel.eventSink) {
        // 最新的蓝牙设备名称，peripheral.name连接后苹果有你缓存，peripheral.name不会被强制更新
        NSString *localName = [advertisementData objectForKey:@"kCBAdvDataLoalName"];
        
        NSMutableDictionary *dic = [NSMutableDictionary dictionary];
        [dic setValue:self.tag forKey:@"tag"];
        [dic setValue:[NSNumber numberWithInteger:peripheral.state] forKey:@"connectState"];
        [dic setValue:localName forKey:@"name"];
        [dic setValue:peripheral.identifier.UUIDString forKey:@"macAddress"];
        [dic setValue:RSSI forKey:@"rssi"];
        if (localName) {
            // 进行更新
            [self.peripherals setObject:peripheral forKey:@"localName"];
        }else{
            // 查找是否有缓存的蓝牙设备
            NSArray *list = self.peripherals.allValues;
            if ([list containsObject:peripheral]) {
                // 有当前外设，进行更新
                [self.peripherals enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
                    if ([peripheral isEqual:obj]) {
                        [self.peripherals setObject:peripheral forKey:key];
                        *stop = YES;
                    }
                }];
            }else{
                // 缓存没有外设，则进行添加
                NSString *uuid = peripheral.identifier.UUIDString;
                [self.peripherals setObject:peripheral forKey:uuid];
                [dic setValue:uuid forKey:@"macAddress"];
            }
        }
        
        self.scanChannel.eventSink(dic);
    }
}

// 3.连接外围设备
// 成功连接指定外设的代理回调
-(void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{
    if ([peripheral.name isEqualToString:self.name]) {
        self.peripheral = peripheral;
        [peripheral setDelegate:self];
        
        // 发现服务
        [peripheral discoverServices:nil];
        
        self.isConnecting = NO;
        if (self.flutterResult) {
            [self cancelConnectTimer];
            self.flutterResult([self connectedGetDataWithPeripheral:peripheral]);
        }
    }
}

// 连接失败后的代理回调
-(void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{
    self.isConnecting = NO;
    if (self.flutterResult) {
        self.flutterResult = nil;
        NSMutableDictionary *res = [self connectedGetDataWithPeripheral:peripheral];
        [res setValue:@0 forKey:@"connected"];
        [self cancelConnectTimer];
        self.flutterResult(res);
    }
}

// 断开蓝牙连接的代理回调
-(void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{
    if ([self.peripheral.identifier.UUIDString isEqualToString:peripheral.identifier.UUIDString]) {
        self.peripheral = nil;
        self.flutterResult(@1);
    }
}

#pragma mark - 外设相关回调
// 4.获得外围设备的服务
// 返回蓝牙服务
-(void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{
    if (error) {
        self.flutterResult(@0);
    }
    if(self.peripheral && [self.peripheral.identifier.UUIDString isEqualToString:peripheral.identifier.UUIDString] && self.service){
        for (CBService *cbService in peripheral.services) {
            if ([cbService.UUID.UUIDString isEqualToString:self.service]) {
                [peripheral discoverCharacteristics:nil forService:cbService];
                break;
            }
        }
    }
}

// 5.获得服务的特征
// 根据服务查找特征值
-(void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error{
    if (error) {
        self.flutterResult(@0);
    }
    if(self.peripheral && [self.peripheral.identifier.UUIDString isEqualToString:peripheral.identifier.UUIDString] && self.character){
        for (CBCharacteristic *characteristic in service.characteristics) {
            if ([characteristic.UUID.UUIDString isEqualToString:self.character]) {
                if (characteristic.properties == CBCharacteristicPropertyRead) {
                    // 读数据
                    [peripheral readValueForCharacteristic:characteristic];
                }else if(characteristic.properties == CBCharacteristicPropertyWrite){
                    // 写数据
                    [peripheral setNotifyValue:YES forCharacteristic:characteristic];
                }else if(characteristic.properties == CBCharacteristicPropertyNotify){
                    // 通知订阅
                    [peripheral setNotifyValue:YES forCharacteristic:characteristic];
                }
                self.flutterResult(@1);
                break;
            }
        }
    }
}

// 6.从外围设备读数据（直接读取和订阅两种方法）
-(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(nonnull CBCharacteristic *)characteristic error:(nullable NSError *)error{
    
}

// 7.



#pragma mark - 向flutter发送状态
-(void)sendBleState{
    if(self.enableChannel && self.enableChannel.eventSink){
        NSMutableDictionary *info = [NSMutableDictionary dictionary];
        [info setValue:[NSNumber numberWithBool:self.isOpen] forKey:@"enable"];
        self.enableChannel.eventSink(info);
    }
}

#pragma mark - 开始扫描
-(void)startScan{
    // CBCentralManagerScanOptionAllowDuplicatesKey为YES，表示
    [self.manager scanForPeripheralsWithServices:nil options:@{CBCentralManagerScanOptionAllowDuplicatesKey:@YES}];
}

#pragma mark - 停止扫描
-(void)stopScan{
    [self.manager stopScan];
}

#pragma mark - 扫描超时
-(void)scanTimeout{
    if (self.scanChannel && self.scanChannel.eventSink) {
        NSMutableDictionary *dic = [NSMutableDictionary dictionary];
        [dic setValue:self.tag forKey:@"tag"];
        [dic setValue:@1 forKey:@"isComplete"];
        self.scanChannel.eventSink(dic);
    }
    [self stopScan];
}

#pragma mark - 连接超时处理
-(void)connectTimeout:(FlutterResult)result{
    result(@{@"connected":@0});
}

#pragma mark - 连接成功获取相应的数据
-(NSMutableDictionary *)connectedGetDataWithPeripheral:(CBPeripheral *)peripheral{
    NSMutableDictionary *res = [NSMutableDictionary dictionary];
    [res setValue:@1 forKey:@"connected"];
    //获取设备服务
    NSArray<CBService *> *services = peripheral.services;
    NSMutableArray *services_array = [NSMutableArray array];
    for (CBService *service in services) {
        NSMutableDictionary *services_dic = [NSMutableDictionary dictionary];
        [services_dic setValue:service.UUID.UUIDString forKey:@"uuid"];
        NSArray<CBCharacteristic *> *characteristics = service.characteristics;
        for (CBCharacteristic *character in characteristics) {
            NSMutableDictionary *character_dic = [NSMutableDictionary dictionary];
            [character_dic setValue:character.UUID.UUIDString forKey:@"uuid"];
            [services_dic setValue:character_dic forKey:@"characters"];
            
            NSArray<CBDescriptor *> *descriptors = character.descriptors;
            for (CBDescriptor *descriptor in descriptors) {
                NSMutableDictionary *descriptor_dic = [NSMutableDictionary dictionary];
                [descriptor_dic setValue:descriptor.UUID.UUIDString forKey:@"uuid"];
                [descriptor_dic setValue:descriptor.value forKey:@"value"];
                [character_dic setValue:descriptor_dic forKey:@"descriptors"];
            }
        }
        [services_array addObject:services_dic];
    }
    [res setValue:services_array forKey:@"services"];
    return res;
}

#pragma mark - 取消扫描超时定时器
-(void)cancelScanTimer{
    [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(startScan) object:nil];
}

#pragma mark - 取消连接超时定时器
-(void)cancelConnectTimer{
    [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(connectTimeout:) object:nil];
}


#pragma mark - 生成唯一ID方法
-(NSString *)getUniqueId{
    CFUUIDRef uuidRef = CFUUIDCreate(NULL);

    CFStringRef uuidStringRef = CFUUIDCreateString(NULL, uuidRef);

    CFRelease(uuidRef);
    NSString *uniqueId = (__bridge NSString *)uuidStringRef;
    return uniqueId;
}
@end
